import 'dart:async';
import 'dart:io';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:flutter_svg_test/common/test_page.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter/services.dart' show AssetBundle;

class LoadersTestPage extends TestPage {
  LoadersTestPage(super.title) {
    group('BytesLoader()', () {
      BytesLoader loader = const _bytesLoader();
      test('BytesLoader().loadBytes()', () async {
        svg.cache.clear();
        svg.cache.maximumSize = 100;
        final ByteData bytes = await loader.loadBytes(null);
        expect(bytes);
      });

      test('BytesLoader().cacheKey()', () {
        svg.cache.clear();
        svg.cache.maximumSize = 100;
        final Object key = loader.cacheKey(null);
        expect(key);
      });
    });

    group('ColorMapper()', () {
      test('在SvgLoader()中更新colorMapper缓存', () async {
        svg.cache.clear();
        svg.cache.maximumSize = 100;
        const TestLoader loaderA = TestLoader();
        const TestLoader loaderB = TestLoader(colorMapper: _TestColorMapper());
        final ByteData bytesA = await loaderA.loadBytes(null);
        final ByteData bytesB = await loaderB.loadBytes(null);
        expect(identical(bytesA, bytesB));
        expect(svg.cache.count);
      });
    });

    group('PictureInfo', () {
      test('PictureInfo.picture', () async {
        final PictureInfo pictureInfo = await vg.loadPicture(SvgStringLoader(svgString), null);
        expect(pictureInfo.picture.toString());
      });

      test('PictureInfo.size', () async {
        final PictureInfo pictureInfo = await vg.loadPicture(SvgStringLoader(svgString), null);
        expect(pictureInfo.size);
      });
    });

    group('PictureProvider', () {
      test('PictureProvider()', () {
        expect(PictureProvider());
      });
    });

    group('SvgAssetLoader', () {
      List<int> bytes = svgString.codeUnits;
      Uint8List list = Uint8List.fromList(bytes);
      ByteData value = ByteData.view(list.buffer);
      final AssetBundle bundle = _assetBundle(<String, ByteData>{
        'SvgAssetLoader Test': Uint8List(0).buffer.asByteData(),
        'packages/packageName/foo': Uint8List(1).buffer.asByteData(),
      });
      SvgAssetLoader svgAssetLoader = SvgAssetLoader('SvgAssetLoader Test', assetBundle: bundle);
      test('SvgAssetLoader().assetBundle', () {
        expect(svgAssetLoader.assetBundle);
      });
      test('SvgAssetLoader().assetName', () {
        expect(svgAssetLoader.assetName);
      });
      test('SvgAssetLoader().colorMapper', () {
        expect(svgAssetLoader.colorMapper);
      });
      test('SvgAssetLoader().packageName', () {
        expect(svgAssetLoader.packageName);
      });
      test('SvgAssetLoader().cacheKey()', () {
        expect(svgAssetLoader.cacheKey(null));
      });
      test('SvgAssetLoader().loadBytes()', () {
        expect(svgAssetLoader.loadBytes(null));
      });
      test('SvgAssetLoader().prepareMessage()', () {
        expect(svgAssetLoader.prepareMessage(null));
      });
      test('SvgAssetLoader().provideSvg()', () {
        expect(svgAssetLoader.provideSvg(value));
      });
    });
    
    group('SvgBytesLoader', () {
      List<int> bytes = svgString.codeUnits;
      Uint8List list = Uint8List.fromList(bytes);
      SvgBytesLoader svgBytesLoader = SvgBytesLoader(list);
      test('SvgBytesLoader().bytes', () {
        expect(svgBytesLoader.bytes);
      });
      test('SvgBytesLoader().colorMapper', () {
        expect(svgBytesLoader.colorMapper);
      });
      test('SvgBytesLoader().cacheKey()', () {
        expect(svgBytesLoader.cacheKey(null));
      });
      test('SvgBytesLoader().loadBytes()', () async {
        final ByteData bytes = await svgBytesLoader.loadBytes(null);
        expect(bytes);
      });
      test('SvgBytesLoader().prepareMessage()', () {
        expect(svgBytesLoader.prepareMessage(null));
      });
      test('SvgBytesLoader().provideSvg()', () {
        svgBytesLoader.provideSvg(getReturn('svgBytesLoader.provideSvg()回调值'));
      });
    });

    group('SvgCacheKey', () {
      SvgCacheKey svgCacheKey = const SvgCacheKey(theme: SvgTheme(), keyData: Object(), colorMapper: _TestColorMapper());
      test('SvgCacheKey().colorMapper', () {
        expect(svgCacheKey.colorMapper);
      });
      test('SvgCacheKey().keyData', () {
        expect(svgCacheKey.keyData);
      });
      test('SvgCacheKey().theme', () {
        expect(svgCacheKey.theme);
      });
    });

    group('SvgFileLoader', () {
      var file = File('example.txt');
      SvgFileLoader svgFileLoader = SvgFileLoader(file);
      test('SvgFileLoader().colorMapper', () {
        expect(svgFileLoader.colorMapper);
      });
      test('SvgFileLoader().file', () {
        expect(svgFileLoader.file);
      });
      test('SvgFileLoader().theme', () {
        expect(svgFileLoader.theme);
      });
      test('SvgFileLoader().cacheKey()', () {
        expect(svgFileLoader.cacheKey(null));
      });
      test('SvgFileLoader().loadBytes() 测试使用空文件，导致出现路径报错', () {
        expect(svgFileLoader.loadBytes(null));
      });
      test('SvgFileLoader().prepareMessage()', () {
        expect(svgFileLoader.prepareMessage(null));
      });
      test('SvgFileLoader().provideSvg() 测试使用空文件，导致出现路径报错', () {
        expect(svgFileLoader.provideSvg(getReturn('svgFileLoader.provideSvg()回调值')));
      });
    });

    group('SvgLoader', () {
      svg.cache.clear();
      svg.cache.maximumSize = 100;
      const TestLoader loader = TestLoader();
      test('SvgLoader().colorMapper', () {
        expect(loader.colorMapper);
      });
      test('SvgLoader().keyName', () {
        expect(loader.keyName);
      });
      test('SvgLoader().theme', () {
        expect(loader.theme);
      });
      test('SvgLoader().cacheKey()', () {
        expect(loader.cacheKey(null));
      });
      test('SvgLoader().loadBytes()', () {
        expect(loader.loadBytes(null));
      });
      test('SvgLoader().prepareMessage()', () {
        expect(loader.prepareMessage(null));
      });
      test('SvgLoader().provideSvg()', () {
        expect(loader.provideSvg(getReturn('SvgLoader.provideSvg()回调值')));
      });
    });
    
    group('SvgNetworkLoader', () {
      List<int> bytes = svgString.codeUnits;
      Uint8List list = Uint8List.fromList(bytes);
      SvgNetworkLoader svgNetworkLoader = SvgNetworkLoader('http://www.baidu.com/');
      test('SvgNetworkLoader().colorMapper', () {
        expect(svgNetworkLoader.colorMapper);
      });
      test('SvgNetworkLoader().keyName', () {
        expect(svgNetworkLoader.headers);
      });
      test('SvgNetworkLoader().theme', () {
        expect(svgNetworkLoader.theme);
      });
      test('SvgNetworkLoader().url', () {
        expect(svgNetworkLoader.url);
      });
      test('SvgNetworkLoader().cacheKey()', () {
        expect(svgNetworkLoader.cacheKey(null));
      });
      test('SvgNetworkLoader().loadBytes()', () {
        expect(svgNetworkLoader.loadBytes(null));
      });
      test('SvgNetworkLoader().prepareMessage()', () {
        expect(svgNetworkLoader.prepareMessage(null));
      });
      test('SvgNetworkLoader().provideSvg()', () {
        expect(svgNetworkLoader.provideSvg(list));
      });
    });

    group('SvgStringLoader', () {
      SvgStringLoader svgStringLoader = SvgStringLoader(svgString);
      test('SvgStringLoader().colorMapper', () {
        expect(svgStringLoader.colorMapper);
      });
      test('SvgStringLoader().theme', () {
        expect(svgStringLoader.theme);
      });
      test('SvgStringLoader().cacheKey()', () {
        expect(svgStringLoader.cacheKey(null));
      });
      test('SvgStringLoader().loadBytes()', () {
        expect(svgStringLoader.loadBytes(null));
      });
      test('SvgStringLoader().prepareMessage()', () {
        expect(svgStringLoader.prepareMessage(null));
      });
      test('SvgStringLoader().provideSvg()', () {
        expect(svgStringLoader.provideSvg(getReturn('SvgStringLoader.provideSvg()回调值')));
      });
    });

    group('SvgTheme()', () {
      SvgTheme svgTheme = const SvgTheme(currentColor: Colors.blue, fontSize: 14, xHeight: 200);

      test('SvgTheme().currentColor', () {
        expect(svgTheme.currentColor);
      });

      test('SvgTheme().fontSize', () {
        expect(svgTheme.fontSize);
      });

      test('SvgTheme().xHeight', () {
        expect(svgTheme.xHeight);
      });

      test('SvgTheme().toVgTheme()', () {
        expect(svgTheme.toVgTheme());
      });
    });
  }

}

String svgString = '''
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 166 202">
  <defs>
    <linearGradient id="triangleGradient">
      <stop offset="20%" stop-color="#000000" stop-opacity=".55" />
      <stop offset="85%" stop-color="#616161" stop-opacity=".01" />
    </linearGradient>
    <linearGradient id="rectangleGradient" x1="0%" x2="0%" y1="0%" y2="100%">
      <stop offset="20%" stop-color="#000000" stop-opacity=".15" />
      <stop offset="85%" stop-color="#616161" stop-opacity=".01" />
    </linearGradient>
  </defs>
  <path fill="#42A5F5" fill-opacity=".8" d="M37.7 128.9 9.8 101 100.4 10.4 156.2 10.4" />
  <path fill="#42A5F5" fill-opacity=".8" d="M156.2 94 100.4 94 79.5 114.9 107.4 142.8" />
  <path fill="#0D47A1" d="M79.5 170.7 100.4 191.6 156.2 191.6 156.2 191.6 107.4 142.8" />
  <g transform="matrix(0.7071, -0.7071, 0.7071, 0.7071, -77.667, 98.057)">
    <rect width="39.4" height="39.4" x="59.8" y="123.1" fill="#42A5F5" />
    <rect width="39.4" height="5.5" x="59.8" y="162.5" fill="url(#rectangleGradient)" />
  </g>
  <path d="M79.5 170.7 120.9 156.4 107.4 142.8" fill="url(#triangleGradient)" />
</svg>
''';

void getReturn(String message) {
  expect(message);
}

class _assetBundle extends AssetBundle {

  _assetBundle(this.map);

  final Map<String, ByteData> map;

  @override
  Future<ByteData> load(String key) async {
    return map[key]!;
  }

  @override
  Future<T> loadStructuredData<T>(String key, Future<T> Function(String value) parser) {
    // TODO: implement loadStructuredData
    throw UnimplementedError();
  }
  
}

class _bytesLoader extends BytesLoader {
  const _bytesLoader();

  @override
  Future<ByteData> loadBytes(BuildContext? context) async {
    return ByteData(8);
  }

  Object cacheKey(BuildContext? context) => this;

}

class TestLoader extends SvgLoader<void> {
  const TestLoader({this.keyName = 'A', super.theme, super.colorMapper});

  final String keyName;

  @override
  String provideSvg(void message) {
    return '<svg width="10" height="10"></svg>';
  }

  @override
  SvgCacheKey cacheKey(BuildContext? context) {
    return SvgCacheKey(
        theme: theme, colorMapper: colorMapper, keyData: keyName);
  }
}

class _TestColorMapper extends ColorMapper {
  const _TestColorMapper();

  @override
  Color substitute(
      String? id, String elementName, String attributeName, Color color) {
    return color;
  }
}